%%% $Id$
%%%--------------------------------------------------------------------
%%%
%%% Copyright (c) 2008 Vance Shipley
%%% @author Vance Shipley <vance.shipley@clasix.net>
%%% 
%%%--------------------------------------------------------------------
%%% @doc Library of common functions for dvd reading test suites.
%%%--------------------------------------------------------------------
%%%
-module(dvd_read_lib).

%% common_test callbacks
-export([init_per_suite/1, end_per_suite/1]).

%% our API for test suites
-export([find_dvd/0, find_dvd/1, list_vts/1,
			open_vmg/0, open_vts/0, open_file/1,
			read/3, get_vmg/0, get_vmg/1, get_vts/0, get_vts/1]).
-export([pretty_print/1]).

-include("../include/dvd_ifo.hrl").
-include_lib("kernel/include/file.hrl").
-include_lib("common_test/include/ct.hrl").

%% @spec (Config) -> Config
%% 	Config = [tuple()]
%% @doc Initiation before the whole suite.
%%
init_per_suite(Config) ->
   Config.

%% @spec (Config) -> any()
%% 	Config = [tuple()]
%% @doc Cleanup after the whole suite.
%%
end_per_suite(_Config) ->
	ok.

%% @spec () -> string()
%% @doc Find the pathname for a mounted DVD-Video file system.
%%
find_dvd() ->
	{ok, Volumes} = file:list_dir("/Volumes"),
	find_dvd(Volumes).
%% @hidden
find_dvd([H | T]) ->
	Pathname = "/Volumes/" ++ H ++ "/VIDEO_TS/",
	case file:list_dir(Pathname) of
		{error, _Reason} ->
			find_dvd(T);
		{ok, _Files} ->
			Pathname
	end;
find_dvd([]) ->
	erlang:error(enoent).

%% @spec (VideoDir::string()) -> [string()]
%% @doc List video title set IFO files.
%%
list_vts(VideoDir) ->
	{ok, Files} = file:list_dir(VideoDir),
	F1 = fun([$V, $T, $S, $_, _, _, $_, _, $., $I, $F, $O]) ->
				true;
			(_) ->
				false
	end,
	lists:filter(F1, Files).

%% @spec () -> io_device()
%% @doc Find and open a Video Manager IFO file.
%%
open_vmg() ->
	DvdDir = find_dvd(),
	open_file(DvdDir ++ "VIDEO_TS.IFO").

%% @spec () -> io_device()
%% @doc Find and open a Video Title Set IFO file.
%%
open_vts() ->
	DvdDir = find_dvd(),
	open_file(DvdDir ++ "VTS_01_0.IFO").

%% @spec (Filename::string()) -> io_device()
%% @doc Open the file at the given pathname.
%%
open_file(Filename) ->
	case file:open(Filename, [read, binary, raw]) of
		{ok, IoDevice} ->
			IoDevice;
		{error, Reason} ->
			erlang:error(Reason)
	end.

%% @spec (IoDevice::io_device(), Offset::integer(), Amount::integer())
%% 		-> binary()
%% @doc Read Amount of bytes from the file device starting at Offset.
%%
read(IoDevice, Offset, Amount) ->
	case file:pread(IoDevice, Offset, Amount) of
		{ok, Data} ->
			Data;
		eof ->
			erlang:error(eof);
		{error, Reason} ->
			erlang:error(Reason)
	end.

%% @spec () -> video_manager()
%% @doc Find and return a Video Manager Information Table.
%%
get_vmg() ->
	IoDevice = open_vmg(),
	get_vmg(IoDevice).

%% @spec () -> video_manager()
%% @doc Return a Video Manager Information Table.
%%
get_vmg(Filename) when is_list(Filename) ->
	get_vmg(open_file(Filename));
get_vmg(IoDevice) when is_record(IoDevice, file_descriptor) ->
	Bin = read(IoDevice, 0, ?video_manager_size),
	dvd_ifo:video_manager(Bin).

%% @spec () -> video_title_set()
%% @doc Find and return a Video Title Set Information Table.
%%
get_vts() ->
	IoDevice = open_vts(),
	get_vts(IoDevice).

%% @spec () -> video_title_set()
%% @doc Return a Video Title Set Information Table.
%%
get_vts(Filename) when is_list(Filename) ->
	get_vts(open_file(Filename));
get_vts(IoDevice) when is_record(IoDevice, file_descriptor) ->
	Bin = read(IoDevice, 0, ?video_title_set_size),
	dvd_ifo:video_title_set(Bin).

%% @spec (Record::tuple()) -> string()
%% @doc Return a string describing the record.
%%
pretty_print(Record) ->
  io_lib_pretty:print(Record, fun pretty_print/2).
% @idden
pretty_print(video_manager, N) ->
	N = record_info(size, video_manager) - 1,
	record_info(fields, video_manager);
pretty_print(video_title_set, N) ->
	N = record_info(size, video_title_set) - 1,
	record_info(fields, video_title_set);
pretty_print(video_attributes, N) ->
	N = record_info(size, video_attributes) - 1,
	record_info(fields, video_attributes);
pretty_print(audio_attributes, N) ->
	N = record_info(size, audio_attributes) - 1,
	record_info(fields, audio_attributes);
pretty_print(karaoke_attributes, N) ->
	N = record_info(size, karaoke_attributes) - 1,
	record_info(fields, karaoke_attributes);
pretty_print(surround_attributes, N) ->
	N = record_info(size, surround_attributes) - 1,
	record_info(fields, surround_attributes);
pretty_print(subpicture_attributes, N) ->
	N = record_info(size, subpicture_attributes) - 1,
	record_info(fields, subpicture_attributes);
pretty_print(user_operations, N) ->
	N = record_info(size, user_operations) - 1,
	record_info(fields, user_operations);
pretty_print(program_chain, N) ->
	N = record_info(size, program_chain) - 1,
	record_info(fields, program_chain);
pretty_print(title, N) ->
	N = record_info(size, title) - 1,
	record_info(fields, title);
pretty_print(language_unit, N) ->
	N = record_info(size, language_unit) - 1,
	record_info(fields, language_unit);
pretty_print(menu_program_chain, N) ->
	N = record_info(size, menu_program_chain) - 1,
	record_info(fields, menu_program_chain);
pretty_print(dvd_time, N) ->
	N = record_info(size, dvd_time) - 1,
	record_info(fields, dvd_time);
pretty_print(command_table, N) ->
	N = record_info(size, command_table) - 1,
	record_info(fields, command_table);
pretty_print(cell_playback, N) ->
	N = record_info(size, cell_playback) - 1,
	record_info(fields, cell_playback);
pretty_print(multichannel_extension, N) ->
	N = record_info(size, multichannel_extension) - 1,
	record_info(fields, multichannel_extension);
pretty_print(_, _) ->
  no.

